using System;
using System.Data;
using System.Data.Linq;
using System.Transactions;
using Rhinestone.Shared;
using IsolationLevel = System.Data.IsolationLevel;

namespace LinqRepositorySample.Data.LinqToSql
{
    public class LinqUnitOfWork : IUnitOfWork
    {
        #region fields
        private DataContext _currentContext;
        private LinqTransaction _currentTransaction;
        private bool _disposed;
        #endregion

        #region .ctor
        public LinqUnitOfWork(DataContext context)
        {
            Guard.Against<ArgumentNullException>(context == null, "Expected a non-null data context.");
            _currentContext = context;
        }
        #endregion

        #region properties
        public DataContext Context
        {
            get { return _currentContext; }
        }
        #endregion

        #region Implementation of IDisposable
        public void Dispose()
        {
            if (!_disposed)
            {
                Dispose(true);
                GC.SuppressFinalize(this);
                _disposed = true;
            }
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_currentTransaction != null)
                {
                    _currentTransaction.Dispose();
                    _currentTransaction = null;
                }
                if (_currentContext != null)
                {
                    _currentContext.Dispose();
                    _currentContext = null;
                }
            }
        }
        #endregion

        #region Implementation of IUnitOfWork
        public ITransaction BeginTransaction()
        {
            return BeginTransaction(IsolationLevel.ReadCommitted);
        }

        public ITransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            TransactionOptions options = new TransactionOptions();
            options.IsolationLevel = IsolationConverter.ToTransactionsIsolation(isolationLevel);
            TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options);
            return new LinqTransaction(this, scope);
        }

        public void Flush()
        {
            _currentContext.SubmitChanges();
        }

        public void TransactionalFlush()
        {
            TransactionalFlush(IsolationLevel.ReadCommitted);
        }

        public void TransactionalFlush(IsolationLevel isolationLevel)
        {
            using (ITransaction transaction = BeginTransaction(isolationLevel))
            {
                _currentContext.SubmitChanges();
                transaction.Commit();
            }
        }

        public bool IsInTransaction
        {
            get { return Transaction.Current == null ; }
        }
        #endregion

        #region methods
        public void ReleaseTransaction()
        {
            _currentTransaction = null;
        }
        #endregion
    }
}